package com.dubbo.framework.protocol.dubbo;

import com.dubbo.framework.Invocation;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.Callable;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

/**
 * @author by Mr. Li 2021/4/30 14:10
 */
@Slf4j
public class NettyClientHandler extends ChannelInboundHandlerAdapter implements Callable {

    public final Object lock = new Object();
    public final ReentrantLock reentrantLock = new ReentrantLock();
    public final Condition condition = reentrantLock.newCondition();


    private ChannelHandlerContext context;
    private Invocation invocation;
    private String result;

    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        this.context = ctx;
    }

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        log.info(">>>>>>>>>>>>>>>>>>>>>>>>channelRead callback");
        this.result = msg.toString();
        reentrantLock.lock();
        try {
            log.info(">>>>>>>>>>>>>>>>>>>>>>>>唤醒等待线程.....");
            condition.signal();
        } finally {
            reentrantLock.unlock();
        }
        //synchronized (lock) {
        //    lock.notifyAll();
        //}
    }

    @Override
    public Object call() throws Exception {
        context.writeAndFlush(this.invocation);

        reentrantLock.lock();
        try {
            log.info(">>>>>>>>>>>>>>>>>>>>>>>>等待channelRead触发");
            condition.await();
        } finally {
            reentrantLock.unlock();
        }

        //synchronized (lock) {
        //    lock.wait();
        //}
        log.info(">>>>>>>>>>>>>>>>>>>>>>>>线程唤醒：{}", result);
        return result;
    }

    public void setInvocation(Invocation invocation) {
        this.invocation = invocation;
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        log.info("发生异常 ctx：{}，ex：{}", ctx, cause);
    }
}
